#pragma once
#include <Rz/Object.h>
#include <Rz/Collections/List.h>
#include <Rz/Graphics/Math/Matrix4.h>

RZ_CLASS_FWD_DECL3(Rz, Graphics, Scene, RootNode);

namespace Rz { namespace Graphics { namespace Scene {

enum class NodeType
{
	None,
	Root,
	Camera,
	Light,
	Mesh
};

class Node :
	public Object
{
	public:
		RZ_RTTI(Rz::Graphics::Scene, Node);
		RZ_RTTI_IMPLEMENTS(Object);
		RZ_RTTI_END;

		typedef Collections::List<Ptr<Node>> Collection;

		Node();

		virtual const String& GetNodeName() const;
		virtual void SetNodeName(const String& name);

		virtual bool IsVisible() const;
		virtual bool IsRoot() const;

		NodeType GetNodeType() const;

		virtual bool HasParent() const;

		virtual const Node* GetParent() const;
		virtual Node* GetParent();
		virtual void SetParent(Node* newParent);

		virtual void Add(Node* node);

		virtual size_t GetChildrenCount() const;

		virtual const Node::Collection GetChildren() const;
		virtual Node::Collection GetChildren();

		virtual const Node* GetChild(size_t index) const;
		virtual Node* GetChild(size_t index);

		virtual const RootNode* GetRootNode() const;
		virtual RootNode* GetRootNode();

		virtual void Show(bool show = true);
		virtual void Hide();

		virtual const Math::Matrix4& GetMatrix() const;
		virtual void SetMatrix(const Math::Matrix4& matrix);
		virtual const Math::Matrix4& GetWorldMatrix() const;
		virtual const Math::Matrix3& GetNormalMatrix() const;
		virtual const Math::Matrix4& GetInverseMatrix() const;

	protected:
		Node(NodeType type);
		void SetNodeType(NodeType nodeType);
		void MakeWorldMatrixDirty();
		virtual bool IsDirty() const;

	private:
		bool _visible;

		NodeType _nodeType;
		String _nodeName;
		Ptr<Node> _parent;
		Node::Collection _children;
		Math::Matrix4 _matrix;

		mutable bool _dirtyWorldMatrix;
		mutable Math::Matrix3 _normalMatrix;
		mutable Math::Matrix4 _worldMatrix;
		mutable Math::Matrix4 _inverseMatrix;
};

} } }
